package cheme.ProcessEditor.Figures.Util;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;

public class PositionCalculator
{
	public enum Position
	{
		TopLeft,	Top,	TopRight, 
		Left,		Center,	Right,
		BottomLeft,	Bottom,	BottomRight
	};
	
	public enum RelativePosition
	{
		OutTopOutLeft,		OutTopInLeft,		OutTop,		OutTopInRight,		OutTopOutRight, 
		InTopOutLeft,		InTopInLeft,		InTop,		InTopInRight,		InTopOutRight,
		OutLeft,			InLeft,				Center,		InRight, 			OutRight,
		InBottomOutLeft,	InBottomInLeft,		InBottom,	InBottomInRight,	InBottomOutRight,
		OutBottomOutLeft,	OutBottomInLeft,	OutBottom,	OutBottomInRight, 	OutBottomOutRight
	};
	
	public static Rectangle getRelativeRectangle(Rectangle basis, Rectangle toLocate, RelativePosition position)
	{
		Rectangle result = null;
		switch (position)
		{
		case OutTop:
			result = getRelativeRectangle(getPoint(basis, Position.Top), toLocate, Position.Top);
			break;
		case InTop:
			result = getRelativeRectangle(getPoint(basis, Position.Top), toLocate, Position.Bottom);
			break;
			
		case OutBottom:
			result = getRelativeRectangle(getPoint(basis, Position.Bottom), toLocate, Position.Bottom);
			break;
		case InBottom:
			result = getRelativeRectangle(getPoint(basis, Position.Bottom), toLocate, Position.Top);
			break;
			
		case OutLeft:
			result = getRelativeRectangle(getPoint(basis, Position.Left), toLocate, Position.Left);
			break;
		case InLeft:
			result = getRelativeRectangle(getPoint(basis, Position.Left), toLocate, Position.Right);
			break;
			
		case InRight:
			result = getRelativeRectangle(getPoint(basis, Position.Right), toLocate, Position.Left);
			break;
		case OutRight:
			result = getRelativeRectangle(getPoint(basis, Position.Right), toLocate, Position.Right);
			break;

		case Center:
			result = getRelativeRectangle(getPoint(basis, Position.Center), toLocate, Position.Center);
			break;
		
		case OutTopOutLeft:
			result = getRelativeRectangle(getPoint(basis, Position.TopLeft), toLocate, Position.TopLeft);
			break;
		case OutTopInLeft:
			result = getRelativeRectangle(getPoint(basis, Position.TopLeft), toLocate, Position.TopRight);
			break;
		case InTopOutLeft:
			result = getRelativeRectangle(getPoint(basis, Position.TopLeft), toLocate, Position.BottomLeft);
			break;
		case InTopInLeft:
			result = getRelativeRectangle(getPoint(basis, Position.TopLeft), toLocate, Position.BottomRight);
			break;

		case OutTopInRight:
			result = getRelativeRectangle(getPoint(basis, Position.TopRight), toLocate, Position.TopLeft);
			break;
		case OutTopOutRight:
			result = getRelativeRectangle(getPoint(basis, Position.TopRight), toLocate, Position.TopRight);
			break;
		case InTopInRight:
			result = getRelativeRectangle(getPoint(basis, Position.TopRight), toLocate, Position.BottomLeft);
			break;
		case InTopOutRight:
			result = getRelativeRectangle(getPoint(basis, Position.TopRight), toLocate, Position.BottomRight);
			break;

		case InBottomOutLeft:
			result = getRelativeRectangle(getPoint(basis, Position.BottomLeft), toLocate, Position.TopLeft);
			break;
		case InBottomInLeft:
			result = getRelativeRectangle(getPoint(basis, Position.BottomLeft), toLocate, Position.TopRight);
			break;
		case OutBottomOutLeft:
			result = getRelativeRectangle(getPoint(basis, Position.BottomLeft), toLocate, Position.BottomLeft);
			break;
		case OutBottomInLeft:
			result = getRelativeRectangle(getPoint(basis, Position.BottomLeft), toLocate, Position.BottomRight);
			break;

		case InBottomInRight:
			result = getRelativeRectangle(getPoint(basis, Position.BottomRight), toLocate, Position.TopLeft);
			break;
		case InBottomOutRight:
			result = getRelativeRectangle(getPoint(basis, Position.BottomRight), toLocate, Position.TopRight);
			break;
		case OutBottomInRight:
			result = getRelativeRectangle(getPoint(basis, Position.BottomRight), toLocate, Position.BottomLeft);
			break;
		case OutBottomOutRight:
			result = getRelativeRectangle(getPoint(basis, Position.BottomRight), toLocate, Position.BottomRight);
			break;

		default: throw new Error();
		}
		
		return result;
	}
	
	public static Rectangle getRelativeRectangle(Point basis, Rectangle toLocate, Position position)
	{
		Rectangle result = toLocate.getCopy();

		int rw = result.width;
		int rh = result.height;
		
		int px = basis.x;
		int py = basis.y;

		switch (position)
		{
		case TopLeft:
			result = result.setLocation(px - rw, py - rh);
			break;
		case Top:
			result = result.setLocation(px - rw / 2, py - rh);
			break;
		case TopRight:
			result = result.setLocation(px, py - rh);
			break;

		case Left:
			result = result.setLocation(px - rw, py - rh / 2);
			break;
		case Center:
			result = result.setLocation(px - rw / 2, py - rh / 2);
			break;
		case Right:
			result = result.setLocation(px, py - rh / 2);
			break;

		case BottomLeft:
			result = result.setLocation(px - rw, py);
			break;
		case Bottom:
			result = result.setLocation(px - rw / 2, py);
			break;
		case BottomRight:
			result = result.setLocation(px, py);
			break;

		default: throw new Error();
		}
		
		return result;
	}
		
	/*
	 * Given a rectangle in absolute coordinates, this method calcualtes a point
	 * described by one of the Position options.
	 */
	public static Point getPoint(Rectangle rect, Position position)
	{
		Point result = null;
		
		switch (position)
		{
		case TopLeft:
			result = rect.getTopLeft();
			break;
		case Top:
			result = new Point(rect.getCenter().x, rect.y);
			break;
		case TopRight:
			result = rect.getTopRight();
			break;

		case Left:
			result = new Point(rect.x, rect.getCenter().y);
			break;
		case Center:
			result = rect.getCenter();
			break;
		case Right:
			result = new Point(rect.x + rect.width, rect.getCenter().y);
			break;

		case BottomLeft:
			result = rect.getBottomLeft();
			break;
		case Bottom:
			result = new Point(rect.getCenter().x, rect.y + rect.height);
			break;
		case BottomRight:
			result = rect.getBottomRight();
			break;

		default: throw new Error();
		}
		
		return result;
	}
}
